﻿//  --------------------------------
//  Copyright (c) AW Systems, Inc. All rights reserved.
//  This source code is made available under the terms of the Microsoft Public License (Ms-PL)
//  http://www.codeplex.com/SLAM/license
//  ---------------------------------

using System;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
using Slam.SharePoint;

namespace Slam.Configuration
{
	/// <summary>
	/// Defines the section of a SLAM configuration stored as XML that defines what types, fields, and associations SLAM
	/// should manage.
	/// </summary>
	public class XmlSqlDataMapping : DataMapping
	{
		#region Private State

		/// <summary>
		/// Regex pattern to validate Guid strings
		/// </summary>
		private static Regex _guidRegex = new Regex(@"^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$", RegexOptions.Compiled);

		/// <summary>
		/// Configuration file XDocument
		/// </summary>
		private XDocument _configXml;

		/// <summary>
		/// The Site Collection for which this DataMapping is defined
		/// </summary>
		private string _siteCollectionName = "";

		private bool _defaultDataMapping;
		private bool _defaultConfirmed;

		#endregion

		public string SiteCollection
		{
			get
			{
				return _siteCollectionName;
			}
		}

		#region Constructors

		public XmlSqlDataMapping(XDocument configurationXml)
		{
			_configXml = configurationXml;
			_defaultDataMapping = true;
			_defaultConfirmed = false;
		}

		public XmlSqlDataMapping(XDocument configurationXml, string siteCollectionName)
		{
			_configXml = configurationXml;
			_siteCollectionName = siteCollectionName;
			_defaultDataMapping = false;
		}

		#endregion

		/// <summary>
		/// Gets all Types, Lists and ContentTypes, in the configuration sorted by ActiveationOrder.
		/// </summary>
		/// <returns>IEnumberable collection of ConfigTypes</returns>
		public override IEnumerable<ConfiguredType> GetAllTypes()
		{
			ConfirmDefaultDataMapping();

			IEnumerable<ConfiguredType> contentTypeNames =
				(from typeNode in _configXml.Root.Elements().Where(mapping => 
					mapping.Name == "DataMapping" &&
					(String.IsNullOrEmpty(_siteCollectionName) ? 
					(mapping.Attribute("SiteCollection") == null || 
					String.IsNullOrEmpty(mapping.Attribute("SiteCollection").Value)) :
					(mapping.Attribute("SiteCollection") != null && 
					mapping.Attribute("SiteCollection").Value.ToLower() == _siteCollectionName.ToLower()))).Elements()
				 let activationOrder = int.Parse(typeNode.Attribute("ActivationOrder").Value)
				 orderby activationOrder
				 select new SqlConfiguredType
				 {
					 Name = typeNode.Attribute("Name") == null ? "" : (string)typeNode.Attribute("Name"),
					 Table = typeNode.Attribute("TableName") == null ? "" : (string)typeNode.Attribute("TableName"),
					 Id = typeNode.Attribute("ID") == null ? "" : (string)typeNode.Attribute("ID"),
					 ContentType = typeNode.Name.LocalName == "ContentType",
					 Site = typeNode.Attribute("Site") == null ? "" : (string)typeNode.Attribute("Site"),
					 SiteCollection = typeNode.Parent.Attribute("SiteCollection") == null ? "" : (string)typeNode.Parent.Attribute("SiteCollection"),
					 TypeIdDefinition = typeNode.Attribute("TypeIdDefinition") == null ? 
										(typeNode.Parent.Attribute("TypeIdDefinition") == null ? "" : typeNode.Parent.Attribute("TypeIdDefinition").Value) : 
										typeNode.Attribute("TypeIdDefinition").Value,
				 }).Cast<ConfiguredType>();

			return contentTypeNames;
		}

		/// <summary>
		/// Gets the database schema for this DataMapping stored in the configuration.
		/// </summary>
		/// <returns></returns>
		public string GetDataSchema()
		{
			ConfirmDefaultDataMapping();

			return _configXml.Root.Elements().Where(node => 
					node.Name == "DataMapping" && 
					(String.IsNullOrEmpty(_siteCollectionName) ? 
					(node.Attribute("SiteCollection") == null || 
					String.IsNullOrEmpty(node.Attribute("SiteCollection").Value)) :
					(node.Attribute("SiteCollection") != null &&
					node.Attribute("SiteCollection").Value.ToLower() == _siteCollectionName.ToLower()))).FirstOrDefault().Attribute("DataSchema").Value;
		}

		/// <summary>
		/// Gets the connection string for this DataMapping stored in the configuration.
		/// </summary>
		/// <returns></returns>
		public string GetConnectionString()
		{
			ConfirmDefaultDataMapping();

			return (string)(_configXml.Root.Elements().Where(node =>
					node.Name == "DataMapping" &&
					(String.IsNullOrEmpty(_siteCollectionName) ?
					(node.Attribute("SiteCollection") == null ||
					String.IsNullOrEmpty(node.Attribute("SiteCollection").Value)) :
					(node.Attribute("SiteCollection") != null &&
					node.Attribute("SiteCollection").Value.ToLower() == _siteCollectionName.ToLower()))).FirstOrDefault().Attribute("ConnectionString")) ?? "";
		}

		/// <summary>
		/// Gets fields that are associations for the given type id or name.
		/// </summary>
		/// <param name="id">Optional unique SharePoint List Guid id as string</param>
		/// <param name="typeName">Name of List or ContentType</param>
		/// <returns>IEnumberable collection of AssociationFields</returns>
		public override IEnumerable<AssociationField> GetTypeAssociations(string id, string typeName)
		{
			ConfirmDefaultDataMapping();

			Guid guidId = Guid.Empty;
			XElement selectedNode = null;

			//Selection precedence follows:
			//If ID is present and a valid, Get type that matches ID
			//If no type matches ID, Get type that has TableName matching the typeName
			//Finally, if nothing yet has been selected get the first node that has Name matching the 
			//typeName

			//Check if ID is present and valid
			if (!String.IsNullOrEmpty(id) && _guidRegex.IsMatch(id))
			{
				guidId = new Guid(id);

				selectedNode = (from typeNode in _configXml.Root.Elements().Where(mapping =>
								   mapping.Name == "DataMapping" &&
								   (String.IsNullOrEmpty(_siteCollectionName) ?
								   (mapping.Attribute("SiteCollection") == null ||
								   String.IsNullOrEmpty(mapping.Attribute("SiteCollection").Value)) :
								   (mapping.Attribute("SiteCollection") != null &&
								   mapping.Attribute("SiteCollection").Value.ToLower() == _siteCollectionName.ToLower()))).Elements()
								where typeNode.Attribute("ID") != null &&
									  typeNode.Attribute("ID").Value == guidId.ToString()
								select typeNode).DefaultIfEmpty().First();
			}

			if (selectedNode == null)
			{
				//Get node matching TableName
				selectedNode = (from typeNode in _configXml.Root.Elements().Where(mapping =>
								   mapping.Name == "DataMapping" &&
								   (String.IsNullOrEmpty(_siteCollectionName) ?
								   (mapping.Attribute("SiteCollection") == null ||
								   String.IsNullOrEmpty(mapping.Attribute("SiteCollection").Value)) :
								   (mapping.Attribute("SiteCollection") != null &&
								   mapping.Attribute("SiteCollection").Value.ToLower() == _siteCollectionName.ToLower()))).Elements()
								where typeNode.Attribute("TableName") != null &&
									  typeNode.Attribute("TableName").Value == typeName
								select typeNode).DefaultIfEmpty().First();

				//If nothing has yet been selected
				if (selectedNode == null)
				{
					//Get node matching type
					selectedNode = (from typeNode in _configXml.Root.Elements().Where(mapping =>
									   mapping.Name == "DataMapping" &&
									   (String.IsNullOrEmpty(_siteCollectionName) ?
									   (mapping.Attribute("SiteCollection") == null ||
									   String.IsNullOrEmpty(mapping.Attribute("SiteCollection").Value)) :
									   (mapping.Attribute("SiteCollection") != null &&
									   mapping.Attribute("SiteCollection").Value.ToLower() == _siteCollectionName.ToLower()))).Elements()
									where typeNode.Attribute("Name").Value == typeName 
									select typeNode).DefaultIfEmpty().First();
				}
			}

			IEnumerable<SqlMappedAssociationField> associations =
				from field in selectedNode.Descendants("Field")
				where field.Attribute("AssociatedTypeName") != null
				select new SqlMappedAssociationField
				{
					AssociationName = (string)field.Attribute("AssociationTableName"),
					AssociatedTypeName = (string)field.Attribute("AssociatedTypeName"),
					Name = (string)field.Attribute("Name"),
					Required = field.Attribute("Required") == null ? false : (string)field.Attribute("Required").Value.ToLower() == "true"
				};

			//Populate association table and column information for each association
			SqlMappedField firstIdField = (SqlMappedField)GetTypeFields(id, typeName).First(f => f is SqlMappedField);
			string firstTableName = GetTypeAttribute("", typeName, "TableName");
			if (String.IsNullOrEmpty(firstTableName))
			{
				firstTableName = FormatName(typeName);
			}
			List<SqlMappedAssociationField> fieldsToReturn = associations.ToList();
			foreach (SqlMappedAssociationField associationField in fieldsToReturn)
			{
				SqlMappedField secondIdField = (SqlMappedField)GetTypeFields(id, associationField.AssociatedTypeName).First(f => f is SqlMappedField);
				string secondTableName = GetTypeAttribute("", associationField.AssociatedTypeName, "TableName");
				if (String.IsNullOrEmpty(secondTableName))
				{
					secondTableName = FormatName(associationField.AssociatedTypeName);
				}
				associationField.FirstAssociatedTypeIdColumn = FormatName(firstTableName != secondTableName ? (firstIdField.Column == secondIdField.Column ? typeName + firstIdField.Column : firstIdField.Column) : (firstIdField.Column.StartsWith(typeName) ? firstIdField.Column : typeName + firstIdField.Column));
				associationField.FirstAssociatedTypeIdSourceColumn = FormatName(firstIdField.Column);
				associationField.FirstAssociatedTypeTableName = firstTableName;
				associationField.FirstAssociatedTypeIdSqlType = firstIdField.SqlType;
				associationField.SecondAssociatedTypeIdColumn = FormatName(firstTableName != secondTableName ? (firstIdField.Column == secondIdField.Column ? associationField.AssociatedTypeName + secondIdField.Column : secondIdField.Column) : (secondIdField.Column.StartsWith(associationField.AssociatedTypeName) ? secondIdField.Column + "2" : associationField.AssociatedTypeName + secondIdField.Column + "2"));
				associationField.SecondAssociatedTypeIdSourceColumn = FormatName(secondIdField.Column);
				associationField.SecondAssociatedTypeTableName = secondTableName;
				associationField.SecondAssociatedTypeIdSqlType = secondIdField.SqlType;
			}

			return fieldsToReturn.Cast<AssociationField>().ToList();
		}

		/// <summary>
		/// Gets a Type's custom attribute by name for the given type id or type name.
		/// </summary>
		/// <param name="id"></param>
		/// <param name="typeName"></param>
		/// <param name="attrbuteName"></param>
		/// <returns></returns>
		public override string GetTypeAttribute(string id, string typeName, string attributeName)
		{
			ConfirmDefaultDataMapping();

			Guid guidId = Guid.Empty;
			string selectedValue = null;

			//Selection precedence follows:
			//If ID is present and a valid, Get type that matches ID
			//If no type matches ID, Get type that has TableName matching the typeName
			//Finally, if nothing yet has been selected get the first node that has Name matching the 
			//typeName

			//Check if ID is present and valid
			if (!String.IsNullOrEmpty(id) && _guidRegex.IsMatch(id))
			{
				guidId = new Guid(id);

				selectedValue = (string)(from typeNode in _configXml.Root.Elements().Where(mapping =>
										   mapping.Name == "DataMapping" &&
										   (String.IsNullOrEmpty(_siteCollectionName) ?
										   (mapping.Attribute("SiteCollection") == null ||
										   String.IsNullOrEmpty(mapping.Attribute("SiteCollection").Value)) :
										   (mapping.Attribute("SiteCollection") != null &&
										   mapping.Attribute("SiteCollection").Value.ToLower() == _siteCollectionName.ToLower()))).Elements()
										 where typeNode.Attribute("ID") != null &&
											   typeNode.Attribute("ID").Value == guidId.ToString() 
										 select typeNode.Attribute(attributeName)).DefaultIfEmpty().First() ?? "";
			}

			if (String.IsNullOrEmpty(selectedValue))
			{
				//Get node matching TableName
				selectedValue = (string)(from typeNode in _configXml.Root.Elements().Where(mapping =>
										   mapping.Name == "DataMapping" &&
										   (String.IsNullOrEmpty(_siteCollectionName) ?
										   (mapping.Attribute("SiteCollection") == null ||
										   String.IsNullOrEmpty(mapping.Attribute("SiteCollection").Value)) :
										   (mapping.Attribute("SiteCollection") != null &&
										   mapping.Attribute("SiteCollection").Value.ToLower() == _siteCollectionName.ToLower()))).Elements()
										 where typeNode.Attribute("TableName") != null &&
											   typeNode.Attribute("TableName").Value == typeName
										 select typeNode.Attribute(attributeName)).DefaultIfEmpty().First() ?? "";

				//If nothing has yet been selected
				if (String.IsNullOrEmpty(selectedValue))
				{
					//Get node matching type
					selectedValue = (string)(from typeNode in _configXml.Root.Elements().Where(mapping =>
											   mapping.Name == "DataMapping" &&
											   (String.IsNullOrEmpty(_siteCollectionName) ?
											   (mapping.Attribute("SiteCollection") == null ||
											   String.IsNullOrEmpty(mapping.Attribute("SiteCollection").Value)) :
											   (mapping.Attribute("SiteCollection") != null &&
											   mapping.Attribute("SiteCollection").Value.ToLower() == _siteCollectionName.ToLower()))).Elements()
											 where typeNode.Attribute("Name").Value == typeName
											 select typeNode.Attribute(attributeName)).DefaultIfEmpty().First() ?? "";
				}
			}

			return selectedValue;
		}

		/// <summary>
		/// Gets fields that are not associations for the given type id or name.
		/// </summary>
		/// <param name="id">Optional unique SharePoint List Guid id as string</param>
		/// <param name="typeName">Name of List or ContentType</param>
		/// <returns></returns>
		public override IEnumerable<Field> GetTypeFields(string id, string typeName)
		{
			ConfirmDefaultDataMapping();

			Guid guidId = Guid.Empty;
			XElement selectedNode = null;

			//Selection precedence follows:
			//If ID is present and a valid, Get type that matches ID
			//If no type matches ID, Get type that has TableName matching the typeName
			//Finally, if nothing yet has been selected get the first node that has Name matching the 
			//typeName

			//Check if ID is present and valid
			if (!String.IsNullOrEmpty(id) && _guidRegex.IsMatch(id))
			{
				guidId = new Guid(id);

				selectedNode = (from typeNode in _configXml.Root.Elements().Where(mapping =>
								   mapping.Name == "DataMapping" &&
								   (String.IsNullOrEmpty(_siteCollectionName) ?
								   (mapping.Attribute("SiteCollection") == null ||
								   String.IsNullOrEmpty(mapping.Attribute("SiteCollection").Value)) :
								   (mapping.Attribute("SiteCollection") != null &&
								   mapping.Attribute("SiteCollection").Value.ToLower() == _siteCollectionName.ToLower()))).Elements()
								where typeNode.Attribute("ID") != null &&
									  typeNode.Attribute("ID").Value == guidId.ToString()
								select typeNode).DefaultIfEmpty().First();
			}

			if (selectedNode == null)
			{
				//Get node matching TableName
				selectedNode = (from typeNode in _configXml.Root.Elements().Where(mapping =>
								   mapping.Name == "DataMapping" &&
								   (String.IsNullOrEmpty(_siteCollectionName) ?
								   (mapping.Attribute("SiteCollection") == null ||
								   String.IsNullOrEmpty(mapping.Attribute("SiteCollection").Value)) :
								   (mapping.Attribute("SiteCollection") != null &&
								   mapping.Attribute("SiteCollection").Value.ToLower() == _siteCollectionName.ToLower()))).Elements()
								where typeNode.Attribute("TableName") != null &&
									  typeNode.Attribute("TableName").Value == typeName 
								select typeNode).DefaultIfEmpty().First();

				//If nothing has yet been selected
				if (selectedNode == null)
				{
					//Get node matching type
					selectedNode = (from typeNode in _configXml.Root.Elements().Where(mapping =>
									   mapping.Name == "DataMapping" &&
									   (String.IsNullOrEmpty(_siteCollectionName) ?
									   (mapping.Attribute("SiteCollection") == null ||
									   String.IsNullOrEmpty(mapping.Attribute("SiteCollection").Value)) :
									   (mapping.Attribute("SiteCollection") != null &&
									   mapping.Attribute("SiteCollection").Value.ToLower() == _siteCollectionName.ToLower()))).Elements()
									where typeNode.Attribute("Name").Value == typeName 
									select typeNode).DefaultIfEmpty().First();
				}
			}

			IEnumerable<SqlMappedField> fields =
				from field in selectedNode.Descendants("Field")
				where field.Attribute("AssociatedTypeName") == null
				select new SqlMappedField
				{
					Column = field.Attribute("Column") == null ? "" : (string)field.Attribute("Column"),
					Name = field.Attribute("Name") == null ? "" : (string)field.Attribute("Name"),
					SharePointType = field.Attribute("SPType") == null ? "" : (string)field.Attribute("SPType"),
					SqlType = field.Attribute("SqlType") == null ? "" : (string)field.Attribute("SqlType"),
					Required = field.Attribute("Required") == null ? false : (string)field.Attribute("Required").Value.ToLower() == "true",
				};

			List<Field> fieldsToReturn = fields.Cast<Field>().ToList();

			//The first field of the fieldsToReturn list will be the identifier of the item
			//If a TypeIdDefition is associated with the given type, determine whether
			//the identifier is a SLAM ID or a List Item ID (UniqueId).
			TypeIdDefinition typeIdDefinition = new TypeIdDefinition();
			string typeIdDefinitionName = GetTypeAttribute("", typeName, "TypeIdDefinition");
			if (String.IsNullOrEmpty(typeIdDefinitionName))
			{
				typeIdDefinitionName = GetTypeIdDefinitionName();
			}
			XmlTypeIdDefinitionSection typeIdDefininitionSection = new XmlTypeIdDefinitionSection(_configXml);

			if (String.IsNullOrEmpty(typeIdDefinitionName))
			{
				typeIdDefinition = typeIdDefininitionSection.Default;
			}
			else
			{
				typeIdDefinition = typeIdDefininitionSection.GetTypeIdDefinition(typeIdDefinitionName);
			}

			SqlMappedField listItemIdField = new SqlMappedField("UniqueId");
			listItemIdField.Column = "ListItemID";
			listItemIdField.Required = true;
			listItemIdField.SqlType = "uniqueidentifier";

			SqlMappedField listIdField = new SqlMappedField("ListID");
			listIdField.Column = "ListID";
			listIdField.Required = true;
			listIdField.SqlType = "uniqueidentifier";

			SqlMappedField listRelativeIdField = new SqlMappedField("ID");
			listRelativeIdField.Column = "ListRelativeID";
			listRelativeIdField.Required = true;
			listRelativeIdField.SqlType = "int";

			if (!String.IsNullOrEmpty(typeIdDefinition.Name)) //Type has TypeIdDefinition
			{
				string tableName = GetTypeAttribute(id, typeName, "TableName");
				if (String.IsNullOrEmpty(tableName))
				{
					tableName = typeName;
				}

				SqlMappedField idField = new SqlMappedField("SLAM ID");
				idField.Column = FormatName(String.IsNullOrEmpty(typeIdDefinition.NameFormat) ? "ID" : typeIdDefinition.NameFormat.Replace("{TypeName}", GetTypeAttribute(id, typeName, "Name")).Replace("{TableName}", tableName));
				idField.Required = true;
				idField.SqlType = typeIdDefinition.SqlType;

				//If Type ID is to a SLAM ID only, add the ID and ListID fields
				if (typeIdDefinition.ReplaceSharePointIds)
				{
					fieldsToReturn.Insert(0, idField);
					fieldsToReturn.Insert(1, listIdField);
				}
				else
				{
					//If Type ID is to include ListItemID and ListRelativeID, SLAM ID is considered the item identifier if Type ID is Primary Key.
					//Otherwise ListItemID is considered the item identifier and will be placed first in the fieldsToReturn list
					if (typeIdDefinition.IsPrimaryKey)
					{
						fieldsToReturn.Insert(0, idField);
						fieldsToReturn.Insert(1, listItemIdField);
						fieldsToReturn.Insert(2, listIdField);
						fieldsToReturn.Insert(3, listRelativeIdField);
					}
					else
					{
						fieldsToReturn.Insert(0, listItemIdField);
						fieldsToReturn.Insert(1, listIdField);
						fieldsToReturn.Insert(2, listRelativeIdField);
						fieldsToReturn.Insert(3, idField);
					}
				}
			}
			else //Type has no TypeIdDefition
			{
				fieldsToReturn.Insert(0, listItemIdField);
				fieldsToReturn.Insert(1, listIdField);
				fieldsToReturn.Insert(2, listRelativeIdField);
			}


			//Add "inline" association columns:
			//If an association's AssociationTableName is missing, the association is treated as a column instead of a table
			IEnumerable<SqlMappedAssociationField> associations =
				from field in selectedNode.Descendants("Field")
				where	field.Attribute("AssociatedTypeName") != null && 
						(field.Attribute("AssociationTableName") == null || String.IsNullOrEmpty(field.Attribute("AssociationTableName").Value))
				select new SqlMappedAssociationField
				{
					AssociationName = (string)field.Attribute("AssociationTableName"),
					AssociatedTypeName = (string)field.Attribute("AssociatedTypeName"),
					Name = (string)field.Attribute("Name"),
					Required = field.Attribute("Required") == null ? false : (string)field.Attribute("Required").Value.ToLower() == "true"
				};

			string firstTableName = GetTypeAttribute("", typeName, "TableName");
			if (String.IsNullOrEmpty(firstTableName))
			{
				firstTableName = FormatName(typeName);
			}

			//Populate association table and column information for each association
			List<SqlMappedAssociationField> associationsToReturn = associations.ToList();
			foreach (SqlMappedAssociationField associationField in associationsToReturn)
			{
				SqlMappedField secondIdField = (SqlMappedField)GetTypeFields(id, associationField.AssociatedTypeName).First(f => f is SqlMappedField);
				string secondTableName = GetTypeAttribute("", associationField.AssociatedTypeName, "TableName");
				if (String.IsNullOrEmpty(secondTableName))
				{
					secondTableName = FormatName(associationField.AssociatedTypeName);
				}
				associationField.FirstAssociatedTypeIdColumn = FormatName(((SqlMappedField)fieldsToReturn[0]).Column == secondIdField.Column ? typeName + ((SqlMappedField)fieldsToReturn[0]).Column : ((SqlMappedField)fieldsToReturn[0]).Column);
				associationField.FirstAssociatedTypeIdSourceColumn = FormatName(((SqlMappedField)fieldsToReturn[0]).Column);
				associationField.FirstAssociatedTypeIdSqlType = ((SqlMappedField)fieldsToReturn[0]).SqlType;
				associationField.FirstAssociatedTypeTableName = firstTableName;
				associationField.SecondAssociatedTypeIdColumn = FormatName(((SqlMappedField)fieldsToReturn[0]).Column == secondIdField.Column ? associationField.AssociatedTypeName + secondIdField.Column : secondIdField.Column);
				//If these columns have the same name it is likely that this association is a self-association
				if (associationField.FirstAssociatedTypeIdColumn == associationField.SecondAssociatedTypeIdColumn)
				{
					associationField.SecondAssociatedTypeIdColumn = associationField.SecondAssociatedTypeIdColumn + "2";
				}
				associationField.SecondAssociatedTypeIdSourceColumn = FormatName(secondIdField.Column);
				associationField.SecondAssociatedTypeIdSqlType = secondIdField.SqlType;
				associationField.SecondAssociatedTypeTableName = secondTableName;
			}

			fieldsToReturn.AddRange(associationsToReturn.Cast<Field>());

			return fieldsToReturn;
		}

		/// <summary>
		/// Gets the name of the type ID definition for this DataMapping stored in the configuration.
		/// </summary>
		/// <returns></returns>
		public string GetTypeIdDefinitionName()
		{
			ConfirmDefaultDataMapping();

			return  (string)(_configXml.Root.Elements().Where(node =>
					node.Name == "DataMapping" &&
					(String.IsNullOrEmpty(_siteCollectionName) ?
					(node.Attribute("SiteCollection") == null ||
					String.IsNullOrEmpty(node.Attribute("SiteCollection").Value)) :
					(node.Attribute("SiteCollection") != null &&
					node.Attribute("SiteCollection").Value.ToLower() == _siteCollectionName.ToLower()))).FirstOrDefault().Attribute("TypeIdDefinition")) ?? "";
		}

		/// <summary>
		/// Gets formatted SQL column name from the given Field.
		/// </summary>
		/// <param name="field">Field from which to get a column name</param>
		/// <returns>The column name</returns>
		public static string GetColumnName(Field field)
		{
			string columnName = field.Name;
			if (field is SqlMappedField)
			{
				SqlMappedField sqlField = (SqlMappedField)field;
				columnName = String.IsNullOrEmpty(sqlField.Column) ? FormatName(field.Name) : sqlField.Column;
			}
			return columnName;
		}

		private static string FormatName(string name)
		{
			return Regex.Replace(name, "[\\W\\s]", "");
		}

		private void ConfirmDefaultDataMapping()
		{
			if (_defaultDataMapping && !_defaultConfirmed)
			{
				XElement selectedNode = (from node in _configXml.Root.Elements()
										 where node.Name == "DataMapping" &&
												 node.Attribute("SiteCollection") == null
										 select node).DefaultIfEmpty().First();

				if (selectedNode == null)
				{
					selectedNode = (from node in _configXml.Root.Elements()
									where node.Name == "DataMapping"
									select node).DefaultIfEmpty().First();

					_siteCollectionName = selectedNode.Attribute("SiteCollection").Value;
				}

				_defaultConfirmed = true;
			}
		}
	}

	
}
